#pragma once
#include"./Message.hpp"
#include <fstream>
#include <sstream>
#include <memory>
#include<vector>
#include <stdlib.h>
#include <cassert>

namespace zlog
{
   //抽象基类
   class FormatItem
   {
    public:
      using Ptr = std::shared_ptr<FormatItem>; 
      virtual void format(ostream& out,const LogMsg& msg) = 0;
   };

   class MsgFormatItem : public FormatItem
   {
    public:
      void format(ostream& out,const LogMsg& msg)
      {
           out << msg._playload;
      }
   };

   class LevelFormatItem : public FormatItem
   {
     public:
        void format(ostream& out,const LogMsg& msg)
        {
            out << LogLevel::toString(msg._level);
        }
   };

   class NameFormatItem : public FormatItem //日志器格式化子类
   {
     public:
        void format(ostream& out,const LogMsg& msg)
        {
            out << msg._logger;
        }
   };

   class ThreadFormatItem : public FormatItem
   {
     public:
        void format(ostream& out,const LogMsg& msg)
        {
            out << msg._tid;
        }
   };

   class TimeFormatItem : public FormatItem
   {
     public:
        TimeFormatItem(const string& fmt = "%H:%M:%S") //默认是时分秒
        :_fmt(fmt)
        {}

        void format(ostream& out,const LogMsg& msg)
        {
            //1.先调用localtime获取时间结构体
             struct tm t;
             localtime_r(&msg.ctime,&t);
            //2.调用strftime转成指定格式
            char buf[32] = {0};
            strftime(buf,31,_fmt.c_str(),&t);
            out << buf;
        }
      private:
         string _fmt;  
   };
    
   class FileFormatItem : public FormatItem
   {
    public:
        void format(ostream& out,const LogMsg& msg)
        {
            out << msg._file;
        }
   };

   class LineFormatItem : public FormatItem
   {
    public:
        void format(ostream& out,const LogMsg& msg)
        {
            out << msg._line;
        }
   };

   class  TabFormatItem : public FormatItem
   {
    public:
        void format(ostream& out,const LogMsg& msg)
        {
            out << "\t";
        }
   };

   class NLineFormatItem : public FormatItem
   {
    public:
        void format(ostream& out,const LogMsg& msg)
        {
            out << "\n";
        }
   };

   //其他消息需要我们将原始字符串传给它
   class OtherFormatItem : public FormatItem
   {
    public:
        OtherFormatItem(const string& str)
        :_str(str)
        {}
        void format(ostream& out,const LogMsg& msg)
        {
            out << _str ;
        }
     private:
       string _str;
   };

   class Formatter
   {
    public:
       using ptr = shared_ptr<Formatter>;
       Formatter(const string& pattern = "[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n")
       :_pattern(pattern)
       {
          assert(parsePattern() == true);
       }
       //对msg进行格式化
       void format(ostream& out,LogMsg& msg)
       {
          for(const auto& item : _items)
          {
              item->format(out,msg);
          }
       }

       string format(LogMsg& msg)
       {
            stringstream ss;
            format(ss,msg);
            return ss.str();
       }

       //对格式化规则字符串进行解析
       bool parsePattern()
       {  
          //ab%%cde[%d{%H:%M:%S}][%p]%T%m%n
          //1.解析格式规则字符串
          int cur = 0;
          vector<pair<string,string>> fmt_order;
          string key;
          string val;
          while(cur < _pattern.size())
          {
             if(_pattern[cur] != '%') //不是以%为起始的认为是原始字符串
             {
                 val += _pattern[cur++];
                 continue;
             }
             //走到这里说明是%:%%的情况注意将cur更新
             if(cur+1 < _pattern.size() && _pattern[cur+1] == '%')
             {
                val += "%";
                cur+=2;
                continue;
             }
             //走到这里说明%后面是格式化字符,原始字符串处理完毕要存进数组里
             if(val.empty() == false)
             {
                fmt_order.push_back(make_pair("",val));
                val.clear();
             }
             cur++;
             if(cur >= _pattern.size())
             {
                 cout << "%后面没有格式化字符!" << endl;
                 return false;
             }
             key = _pattern[cur]; //取出格式化字符
             cur++;
             ///看后面是不是{
             if(cur < _pattern.size() && _pattern[cur] == '{')
             {
                cur++; //跳过{
                while(cur < _pattern.size() && _pattern[cur] != '}')
                      val += _pattern[cur++];
                //子格式不完整
                if(cur == _pattern.size())
                {
                    cout << "子格式不完整" << endl;
                    return false;
                }
                cur++;//跳过}
             }
            fmt_order.push_back(make_pair(key,val));
            key.clear();
            val.clear();
          }
          //2.根据解析到的数据初始化格式化子项数组成员
          for(auto& it : fmt_order)
          {
             _items.push_back(createItem(it.first,it.second)); 
          }
          return true;
       }

    private:
       /* 根据不同的格式化字符创建不同的格式化子项对象 
          key:不同的格式化字符;val:主要是给TimeFormatItem和OtherFormatItem用的
       */
       FormatItem::Ptr createItem(const string& key,const string& val)
       {
          if(key == "d") return make_shared<TimeFormatItem>(val);
          if(key == "t") return make_shared<ThreadFormatItem>();
          if(key == "c") return make_shared<NameFormatItem>();
          if(key == "f") return make_shared<FileFormatItem>();
          if(key == "l") return make_shared<LineFormatItem>();
          if(key == "p") return make_shared<LevelFormatItem>();
          if(key == "T") return make_shared<TabFormatItem>();
          if(key == "m") return make_shared<MsgFormatItem>();
          if(key == "n") return make_shared<NLineFormatItem>();
          //不匹配的情况：1.其他格式化子项
          if(key.empty()) return make_shared<OtherFormatItem>(val);
          //2.不存在的格式化字符
          cout << "不存在的格式化字符!" << endl;
          abort();
          return FormatItem::Ptr();
       }

    private:
       string _pattern; //格式化规则字符串
       vector<FormatItem::Ptr> _items; //格式化子项数组 
   };
}